package string;

/**
 * 字符串String
 * 内部使用一个char数组保存所有在字符,每个字符为2节,存的是该字符unicode编码.
 * 字符串是不变对象,一旦创建内容不可改变,若改变会创建新对象
 */
public class SteingDemo {
    public static void main(String[] args) {
        /*
          字符串常量池
          java在堆内存中开辟了一段空间用于缓存所有字母量形式创建的字符串对象,
          并在后期再次使用该字面量创建字符串时重用对象,避免内存中堆积大量内容一样
          的字符串对象来减小内存开销.
         */
        String s1 = "123abc";//字面量
        String s2 = "123abc";
        //地址相同,说明s2重用了s1对象
        System.out.println(s1==s2);//true
        String s4 = new String("123abc");//new会产生新对象
        System.out.println("s4"+s4);
        System.out.println(s1==s4);//false
        /*
        通常我们判断字符串都是比较内容,因此应当实际字符串的equals方法
         */
        System.out.println(s1.equals(s4));//true
        /*
        由于字符串是不变对象,改变内容会产生新对象
         */
        s1 = s1+"!";//生成一个新的字符串对象123abc!
        System.out.println("s1"+s1);//123abc!
        System.out.println("s2"+s2);//123abc
        System.out.println(s1==s2);//false s1,s2已经不再指向同一个对象了

        /*
        这里触发了一个编译器的特性:
        编译器在编译期间若遇到几个计算表达式,发现在编译器可以确定结果是就会进行计算
        并将结果编译到class文件中,这样一来JVM每次执行字节码文件就无需在计算了.
        下面的代码会被编译器改为:
        String s5 = "123abc";
        也因此s5会重用材料池中的对象,所以地址与s2相同
         */

        String s5 = "123"+"abc";
        System.out.println("s5"+s5);
        System.out.println(s2==s5);

        String s = "123";
        String s6 = s + "abc";
        System.out.println("s6"+s6);
        System.out.println(s2==s6);

        String s7 = 1+2+3+"abc";
        System.out.println(s2==s7);

        String s8 = 1+'2'+3+"abc";
        System.out.println(s2==s8);

        String s9 = 1+"2"+3+"abc";
        System.out.println(s2==s9);
    }
}
